package vns.client.view;

import java.util.ArrayList;
import java.util.List;

import vns.client.VNSmartUI;
import vns.client.helper.NumericTextBox;
import vns.client.helper.RPCCall;
import vns.client.presenter.ObjectDetailPresenter;
import vns.client.service.SupperAdminService;
import vns.client.service.SupperAdminServiceAsync;
import vns.shared.ObjectDTO;
import vns.shared.ObjectPropertyDTO;
import vns.shared.ObjectTypeDTO;
import vns.shared.ObjectValueDTO;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormHandler;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormSubmitEvent;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.datepicker.client.DateBox;

public class ObjectDetailUI extends Composite implements
		ObjectDetailPresenter.Display {

	private List<String> listStringColumn = new ArrayList<String>();
	private static int rowSelectedID;
	private ObjectTypeDTO currentObjectTypeDTO;
	private ObjectDTO currentObjectDTO;
	private List<ObjectPropertyDTO> listObjectPropertyDTO;
	private SupperAdminServiceAsync rpcSAdmin = GWT
			.create(SupperAdminService.class);

	private static ObjectTypeDetailUiBinder uiBinder = GWT
			.create(ObjectTypeDetailUiBinder.class);
	@UiField
	FlexTable flexTable;
	@UiField
	Button btUpdate;
	@UiField
	Button btCancel;

	interface ObjectTypeDetailUiBinder extends UiBinder<Widget, ObjectDetailUI> {
	}

	public ObjectDetailUI() {
		initWidget(uiBinder.createAndBindUi(this));
		bind();
	}

	private void bind() {

		flexTable.setCellPadding(2);
		flexTable.setCellSpacing(0);

		/*
		 * FlexTable Even
		 */
		flexTable.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				getClickedRow(event);

			}
		});

	}

	/***************************************************************************/
	public void renderClickedRow() {
		if (rowSelectedID > 0) {
			HTMLTable.RowFormatter rf = flexTable.getRowFormatter();
			rf.addStyleName(rowSelectedID, "vnsClickedRow");
		}
	}

	public void unrenderClickedRow() {
		if (rowSelectedID > 0) {
			HTMLTable.RowFormatter rf = flexTable.getRowFormatter();
			rf.removeStyleName(rowSelectedID, "vnsClickedRow");
		}
	}

	public int getClickedRow(ClickEvent event) {
		int selectedRow = -1;
		HTMLTable.Cell cell = flexTable.getCellForEvent(event);

		if (cell != null) {
			if (cell.getCellIndex() >= 0) {
				selectedRow = cell.getRowIndex();
			}
			swapClickedRow(selectedRow, cell.getCellIndex());
		}

		return selectedRow;
	}

	private void swapClickedRow(int rowNow, int cellindex) {
		if (rowNow != rowSelectedID && rowNow > 0) {
			unrenderClickedRow();
			setRowEnable(rowSelectedID, false);
			rowSelectedID = rowNow;

			renderClickedRow();
			setRowEnable(rowSelectedID, true);
		} else if (rowNow == rowSelectedID && rowNow > 0) {
			if (cellindex == 0) {
				unrenderClickedRow();
				setRowEnable(rowSelectedID, false);
				rowSelectedID = -1;
			}
		}
	}

	/*
	 * Set Row Enable
	 */
	private void setRowEnable(int row, boolean value) {
		if (row <= flexTable.getRowCount() - 1 && row > 0) {
			// TODO
		}
	}

	/*************************************************************************/
	private void initTableFirst() {
		flexTable.removeAllRows();
		/*
		 * Tên các cột
		 */
		listStringColumn.add("");
		listStringColumn.add("");
		int i = 0;
		// Window.alert("Init Table First");
		for (final String columnName : listStringColumn) {
			flexTable.setHTML(0, i, "<center><b>" + columnName
					+ "</b></center>");
			// Window.alert(listStringColumn.get(i));
			i++;
		}
	}

	protected Widget getWidget(String type, String objectType, String value,
			List<ObjectDTO> listObjectRelated, boolean isReadonly,
			boolean isLinked, boolean multi,
			List<ObjectValueDTO> listValueRelated) {
		// Window.alert("Type:" + type + "|" + objectType + "|" + value );
		if (type.equalsIgnoreCase("string")) {
			TextBox wg = new TextBox();
			wg.setValue(value);
			return wg;
		} else if (type.equalsIgnoreCase("text")) {
			TextArea wg = new TextArea();
			wg.setValue(value);
			return wg;
		} else if (type.equalsIgnoreCase("integer")
				|| type.equalsIgnoreCase("float")
				|| type.equalsIgnoreCase("double")
				|| type.equalsIgnoreCase("long")) {
			NumericTextBox wg = new NumericTextBox();
			wg.setValue(value);
			return wg;
		} else if (type.equalsIgnoreCase("boolean")) {
			CheckBox wg = new CheckBox();
			wg.setValue(Boolean.parseBoolean(value));
			return wg;
		} else if (type.equalsIgnoreCase("password")) {
			PasswordTextBox wg = new PasswordTextBox();
			wg.setValue(value);
			return wg;
		} else if (type.equalsIgnoreCase("date")
				|| type.equalsIgnoreCase("datetime")) {
			DateBox wg = new DateBox();
			DateTimeFormat format = DateTimeFormat.getFormat("dd/MM/yyyy");
			wg.setFormat(new DateBox.DefaultFormat(format));
			if (value != null && value != "")
				wg.setValue(format.parse(value));
			return wg;

		} else if (type.equalsIgnoreCase("key")) {
			ListBox wg = new ListBox(multi);
			wg.addItem("---", "");
			int index = 1;
			for (ObjectDTO o : listObjectRelated) {
				String oKey = KeyFactory.keyToString(o.getId());
				wg.addItem(o.getMain(), oKey);
				for (ObjectValueDTO vDTO : listValueRelated) {
					if (oKey.equals(vDTO.getValue())) {
						wg.setItemSelected(index, true);
					}
				}
				index++;
			}
			return wg;
		} else if (type.equalsIgnoreCase("file")) {

			final FormPanel form = new FormPanel();
			new RPCCall<String>() {

				@Override
				public void onFailure(Throwable caught) {
					Window.alert("Không lấy được upload path!");
				}

				@Override
				public void onSuccess(String result) {
					form.setAction(result);
				}

				@Override
				protected void callService(AsyncCallback<String> cb) {
					rpcSAdmin.test(cb);
				}

			}.retry(3);

			form.setEncoding(FormPanel.ENCODING_MULTIPART);
			form.setMethod(FormPanel.METHOD_POST);

			// Create a panel to hold all of the form widgets.
			VerticalPanel panel = new VerticalPanel();
			form.setWidget(panel);

			// Create a FileUpload widget.
			final FileUpload upload = new FileUpload();
			upload.setName("uploadFormElement");
			panel.add(upload);

			final HTML html = new HTML();
			if (value != null)
				if (!value.equalsIgnoreCase("")) {
					form.setTitle(value);
					String[] IDs = value.split("#");
					html.setHTML("<a href='" + GWT.getHostPageBaseURL()
							+ "serve?blob-key=" + IDs[1] + "> Tải về: "
							+ IDs[0] + "</a>");
				}
			panel.add(html);

			HorizontalPanel hPanel = new HorizontalPanel();
			panel.add(hPanel);

			// Add a 'submit' button.
			Button btSubit = new Button("Tải lên", new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					Button b = (Button) event.getSource();
					if (form.getTitle().equalsIgnoreCase("")) {
						if (upload.getFilename() != null
								&& !upload.getFilename().equalsIgnoreCase("")) {
							form.submit();
							b.setText("Xóa");
						} else {
							VNSmartUI.get().getDialogBoxSub()
									.setText("Chưa chọn file!");
							VNSmartUI.get().getDialogBoxSub().show();
							VNSmartUI.get().getDialogBoxSub().center();
						}
					} else {
						form.reset();
						form.setTitle("");
						html.setHTML("");
						new RPCCall<String>() {

							@Override
							public void onFailure(Throwable caught) {
								Window.alert("Không lấy được upload path!");
							}

							@Override
							public void onSuccess(String result) {
								form.setAction(result);
							}

							@Override
							protected void callService(AsyncCallback<String> cb) {
								rpcSAdmin.test(cb);
							}

						}.retry(3);
						b.setText("Tải lên");
					}
				}
			});
			hPanel.add(btSubit);
			if (value != null)
				if (!value.equals(""))
					btSubit.setText("Xóa");

			// Add an event handler to the form.

			form.addFormHandler(new FormHandler() {

				@Override
				public void onSubmitComplete(FormSubmitCompleteEvent event) {
					html.setHTML("<a href='" + GWT.getHostPageBaseURL()
							+ "serve?blob-key=" + event.getResults()
							+ "> Tải về: " + upload.getFilename() + "</a>");
					form.setTitle(upload.getFilename() + "#"
							+ event.getResults());
				}

				@Override
				public void onSubmit(FormSubmitEvent event) {
					// Window.alert("Submit");
				}
			});
			return form;
		} else
			return null;
	}

	/*
	 * Add Row with Wiget
	 */

	private int addRow(String propertyName, Widget box, boolean isMulti,
			final String opType) {
		int row = flexTable.getRowCount();
		flexTable.setText(row, 0, propertyName);
		if (isMulti && !opType.equalsIgnoreCase("key")) {

			Button bt = new Button("+");
			bt.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					int rowClicked = getClickedRow(event);
					int i = 0;
					for (i = 0; i < getFlexTable().getRowCount()
							- (rowClicked + 1); i++) {
						String text = (getFlexTable().getText(rowClicked + i
								+ 1, 0)).trim();
						if (!text.equals("")) {
							break;
						}
					}
					int rowInserted = getFlexTable().insertRow(
							rowClicked + i + 1);
					Widget newBox = getWidget(opType, null, null, null, false,
							false, false, null);
					getFlexTable().setWidget(rowInserted, 1, newBox);
				}
			});

			flexTable.setWidget(row, 1, box);
			flexTable.setWidget(row, 2, bt);
		} else
			flexTable.setWidget(row, 1, box);

		setRowEnable(row, false);
		return row;
	}

	/*
	 * Update
	 */
	private void update() {
		int row = 1;
		String oKey = null;
		String pKey = null;
		String value = null;
		if (currentObjectDTO.getId() != null)
			oKey = KeyFactory.keyToString(currentObjectDTO.getId());
		for (ObjectPropertyDTO op : currentObjectDTO.getListProperty()) {
			pKey = KeyFactory.keyToString(op.getId());
			int rowConlai = flexTable.getRowCount() - row;
			for (int i = 0; (i < rowConlai) && (row < flexTable.getRowCount()); i++) {
				value = getValueFromWidget(op.getOptypename(), row);
				if (op.getOptypename().equalsIgnoreCase("key")) {
					String[] childValue = value.split("#");
					op.getListObjectValue().clear();
					for (String childVal : childValue) {
						ObjectValueDTO valueDTO = new ObjectValueDTO();
						valueDTO.setObjectKey(oKey);
						valueDTO.setPropertyKey(pKey);
						valueDTO.setValue(childVal);
						op.getListObjectValue().add(valueDTO);
					}
				} else {

					if (value == null)
						value = "";
					else
						value = value.trim();
					if (value.equalsIgnoreCase("")) {
						// delete
						op.getListObjectValue().remove(i);
						i--;
					} else {
						if (i < op.getListObjectValue().size()) {
							// update
							op.getListObjectValue().get(i).setObjectKey(oKey);
							op.getListObjectValue().get(i).setPropertyKey(pKey);
							op.getListObjectValue().get(i).setValue(value);
						} else {
							// create
							ObjectValueDTO valueDTO = new ObjectValueDTO();
							valueDTO.setObjectKey(oKey);
							valueDTO.setPropertyKey(pKey);
							valueDTO.setValue(value);
							op.getListObjectValue().add(valueDTO);
						}
					}
				}
				row++;
				if (row >= flexTable.getRowCount()) {
					break;
				} else {
					String text = flexTable.getText(row, 0).trim();
					if (!text.equalsIgnoreCase("")) {
						break;
					}
				}
			}
		}
		// Window.alert("Ngu ngu");
		// for (ObjectPropertyDTO op : currentObjectDTO.getListProperty()) {
		// Window.alert(op.getName());
		// for (ObjectValueDTO ov : op.getListObjectValue()) {
		// Window.alert(ov.getValue());
		// }
		// }
	}

	// private List<ValueAndName> getValueFromWidgetList(String type, int row) {
	// List<ValueAndName> vans = new ArrayList<ValueAndName>();
	// if (type != null)
	// if (type.equalsIgnoreCase("key")) {
	// MultiselectListBox wg = (MultiselectListBox) flexTable
	// .getWidget(row, 1);
	// vans = wg.getValues();
	// }
	// return vans;
	// }

	private String getValueFromWidget(String type, int row) {
		String value = null;
		// Window.alert("getValueFromWidget:" + type);
		if (type.equalsIgnoreCase("string")) {
			TextBox wg = (TextBox) flexTable.getWidget(row, 1);
			value = wg.getValue();
		} else if (type.equalsIgnoreCase("integer")
				|| type.equalsIgnoreCase("float")
				|| type.equalsIgnoreCase("double")
				|| type.equalsIgnoreCase("long")) {
			NumericTextBox wg = (NumericTextBox) flexTable.getWidget(row, 1);
			value = wg.getValue();
		} else if (type.equalsIgnoreCase("boolean")) {
			CheckBox wg = (CheckBox) flexTable.getWidget(row, 1);
			value = wg.getValue().toString();
		} else if (type.equalsIgnoreCase("password")) {
			PasswordTextBox wg = (PasswordTextBox) flexTable.getWidget(row, 1);
			value = wg.getValue();
		} else if (type.equalsIgnoreCase("date")
				|| type.equalsIgnoreCase("datetime")) {
			DateBox wg = (DateBox) flexTable.getWidget(row, 1);
			value = wg.getTextBox().getValue();
		} else if (type.equalsIgnoreCase("key")) {
			ListBox wg = (ListBox) flexTable.getWidget(row, 1);
			value = "";
			for (int i = 0, l = wg.getItemCount(); i < l; i++) {
				if (wg.isItemSelected(i)) {
					value += wg.getValue(i) + "#";
				}
			}
		} else if (type.equalsIgnoreCase("file")) {
			FormPanel wg = (FormPanel) flexTable.getWidget(row, 1);
			value = wg.getTitle();
		}
		return value;
	}

	/************************************************************/

	/*
	 * Event
	 */

	@UiHandler("btUpdate")
	void onBtUpdateClick(ClickEvent event) {
		update();
	}

	/************************************************************/
	public FlexTable getFlexTable() {
		return flexTable;
	}

	public void setFlexTable(FlexTable flexTable) {
		this.flexTable = flexTable;
	}

	@Override
	public Button getUpdateButton() {
		return btUpdate;
	}

	@Override
	public Button getCancelButton() {
		return btCancel;
	}

	@Override
	public ObjectDTO getCurrentObjectDTO() {
		return currentObjectDTO;
	}

	@Override
	public void setCurrentObjectDTO(ObjectDTO o) {
		currentObjectDTO = o;
	}

	@Override
	public ObjectTypeDTO getCurrentObjectTypeDTO() {
		return currentObjectTypeDTO;
	}

	@Override
	public void setCurrentObjectTypeDTO(ObjectTypeDTO ot) {
		currentObjectTypeDTO = ot;
	}

	@Override
	public List<ObjectPropertyDTO> getListObjectPropertyDTO() {
		return listObjectPropertyDTO;
	}

	@Override
	public void setListObjectPropertyDTO(List<ObjectPropertyDTO> listopt) {
		listObjectPropertyDTO = listopt;
	}

	private String operation;

	@Override
	public String getCurrentOperation() {
		return operation;
	}

	@Override
	public void setCurrentOperation(String operation) {
		this.operation = operation;
	}

	@Override
	public void render() {
		rowSelectedID = -1;
		initTableFirst();
		List<ObjectPropertyDTO> list = currentObjectDTO.getListProperty();
		for (ObjectPropertyDTO op : list) {
			String propertyName = op.getName();
			if (op.getListObjectValue().size() == 0) {
				ObjectValueDTO vDTO = new ObjectValueDTO();
				op.getListObjectValue().add(vDTO);
			}
			for (ObjectValueDTO vDTO : op.getListObjectValue()) {
				addRow(propertyName,
						getWidget(op.getOptypename(), op.getObjtypename(),
								vDTO.getValue(), op.getlistObjectRelated(),
								op.getReadonly(), op.getLinked(),
								op.getMulti(), op.getListObjectValue()),
						op.getMulti(), op.getOptypename());
				propertyName = "";
				if (op.getOptypename().equalsIgnoreCase("key"))
					break;
			}
		}
	}

	@Override
	public boolean checkRequired() {
		int row = 1;
		boolean result = true;
		for (ObjectPropertyDTO pDTO : this.getListObjectPropertyDTO()) {
			if (pDTO.getRequire()) {
				String value = getValueFromWidget(pDTO.getOptypename(), row);
				if (value != null)
					if (value.equalsIgnoreCase(""))
						result = false;
					else
						result = true;
			}
			if (result == false) {
				VNSmartUI.get().getDialogBoxSub()
						.setText("Không được để trống " + pDTO.getName());
				VNSmartUI.get().getDialogBoxSub().show();
				VNSmartUI.get().getDialogBoxSub().center();
				return false;
			}
			row++;
		}
		return true;
	}

}
